MBOOT_MODULEALIGN	EQU	1 << 0
MBOOT_MEMINFO		EQU	1 << 1
MBOOT_FLAGS		EQU	MBOOT_MODULEALIGN | MBOOT_MEMINFO
MBOOT_MAGIC		EQU	0x1BADB002
MBOOT_CHECKSUM		EQU	-(MBOOT_MAGIC + MBOOT_FLAGS)

KERNEL_BASE_ADDR	EQU	0xC0000000
KERNEL_PAGE_NUMBER	EQU	(KERNEL_BASE_ADDR >> 22)

[GLOBAL _start]
[EXTERN	kernelPageDirectory]
[EXTERN	main]

[BITS		32]
[SECTION	.header]
ALIGN	4
DD	MBOOT_MAGIC
DD	MBOOT_FLAGS
DD	MBOOT_CHECKSUM

[SECTION	.text]
_start:
	; Make all segment registers point to the right GDT descriptor.
	MOV	CX, 0x10
	MOV	DS, CX
	MOV	ES, CX
	MOV	FS, CX
	MOV	GS, CX
	MOV	SS, CX
	
	; The stack is at tmp_stack (0xC00.....) but without paging, we would fault.
	; so make ESP pointing to tmp_stack - 0xC0000000.
	; + 0x1000 because the stack grows up.
	MOV	ESP, (tmpStack - KERNEL_BASE_ADDR + 0x1000)

	; Clear EFLAGS
	PUSH	DWORD 0x02
	POPFD

	; Save the Multiboot info structure
	PUSH	EBX
	
	; Save the Multiboot Magic value
	PUSH	EAX

	; Make sure that kernelPageDirectory is clean
	; like memset(kernelPageDirectory, 0, sizeof(kernelPageDirectory));
	MOV	EDI, (kernelPageDirectory - KERNEL_BASE_ADDR)
	MOV	ECX, 1024
	XOR	EAX, EAX
	CLD
	REP	STOSD

	; Identity Map first 4 MB
	MOV	EDI, (kernelPageDirectory - KERNEL_BASE_ADDR)
	MOV	[EDI], DWORD 0x83
	
	; Map first 8 MB at Higher Half space
	ADD	EDI, (KERNEL_PAGE_NUMBER * 4)
	MOV	[EDI], DWORD 0x83
	ADD	EDI, 4
	MOV	[EDI], DWORD 0x00400083

	; Load the address of the page directory in CR3
	MOV	EAX, (kernelPageDirectory - KERNEL_BASE_ADDR)
	MOV	CR3, EAX

	; Enable 4MB pages
	MOV	EAX, CR4
	OR	EAX, 0x00000010
	MOV	CR4, EAX

	; Enable paging
	MOV	EAX, CR0
	OR	EAX, 0xC0010000  ; set the 486 CE (cache enable) and WP bits
	MOV	CR0, EAX

	; Jump to code on 3GB
	LEA	ECX, [AfterPaging]
	JMP	ECX
	
AfterPaging:
	; Remove the identity mapping
	MOV	EDI, kernelPageDirectory
	MOV	[EDI], DWORD 0

	; Update the ESP value... if we PUSH/POP something now it would page fault
	ADD	ESP, KERNEL_BASE_ADDR

	; Reload page dir (clear TLB cache)
	MOV	ECX, CR3
	MOV	CR3, ECX

	CALL	InitPIT

	CALL	main

	CLI
	HLT
	
InitPIT:
	MOV	AL, 0x11
	OUT	0x20, AL
	OUT	0xA0, AL

	MOV	AL, 0x20
	OUT	0x21, AL
	ADD	AL, 8
	OUT	0xA1, AL
	
	MOV	AL, 1
	OUT	0x21, AL
	OUT	0xA1, AL
	
	MOV	AL, 0xFB
	OUT	0x21, AL
	OR	AL, 4
	OUT	0xA1, AL
	
	RET

[SECTION	.bss]
ALIGN	8
tmpStack:
	RESB	0x1000
